﻿var Filter_Instances = [];
var lastBucket;

function Filter(id, type)
{
    this.id = id;
    this.type = type;
    this.container = null;
    this.parent = null;
    this.bucket;
    
    if(type == "GROUP") {
        this.nexo = "";
        this.level = 0;
        this.source = "";
        this.filters = [];
        this.buckets = [];
    }
    else {
        this.field = "";
        this.operation = "";
        this.value = "";
        this.typeValue = "";
    }

    // Public Functions
    this.addGroupFilter = Filter_AddGroupFilter
    this.addConditionFilter = Filter_AddConditionFilter
    this.removeChild = Filter_RemoveChild;
    this.clear = Filter_Clear;
    this.toXml = Filter_ToXml;
    this.fromXml = Filter_FromXml;
    this.clone = Filter_Clone;

    // Private Functions
    this.newChild = Filter_NewChild;
    this.removeChildFromIndex = Filter_RemoveChildFromIndex
    this.parseInnerFilters = Filter_ParseInnerFilters;

    // No guardo referencias a los objetos clonados
    if(this.id!="#clone")
        Filter_Instances[id] = this;
}

// Copio todo menos el container
function Filter_Clone()
{
    var filterClone = new Filter("#clone", this.type);
    
    filterClone.id = this.id;
    filterClone.type = this.type;
    filterClone.parent = this.parent;
    filterClone.bucket = this.bucket;
    
    // copio los inner filters
    if(this.type == "GROUP") {
        filterClone.nexo = "";
        filterClone.level = 0;
        filterClone.buckets = this.buckets.slice();

        for(var i=0; i<this.filters.length; i++) {
            filterClone.filters.push(this.filters[i].clone());
            filterClone.filters[i].parent = filterClone;
        }
        filterClone.source = this.source;    
    }
    else {
        filterClone.field = this.field;
        filterClone.operation = this.operation;
        filterClone.value = this.value;
        filterClone.typeValue = this.typeValue;    
    }
    
    return filterClone;
}

function Filter_UpdateReferences(id, filter)
{
    Filter_Instances[id] = filter;
    
    if(filter.type == "GROUP") {
        for(var i=0; i<filter.filters.length; i++) {
            Filter_UpdateReferences(filter.filters[i].id, filter.filters[i])
        }
    }
}

function Filter_AddGroupFilter(nexo, source)
{
    var newFilter = new Filter(this.newChild(), "GROUP");
    newFilter.level = this.level + 1;
    newFilter.parent = this;
    newFilter.bucket = lastBucket;
    newFilter.source = source;
    
    this.filters.push(newFilter);

    if(nexo) 
        newFilter.nexo = nexo;

    return newFilter;
}

function Filter_AddConditionFilter(field, operation, value, typeValue)
{
    var newFilter = new Filter(this.newChild(), "CONDITION");
    newFilter.parent = this;
    newFilter.bucket = lastBucket;
    
    this.filters.push(newFilter);

    if(field) newFilter.field = field;
    if(operation) newFilter.operation = operation;
    if(value) newFilter.value = value;
    if(typeValue) newFilter.typeValue = typeValue;
    
    return newFilter;
}

function Filter_RemoveChild(idfilter)
{
    var encontro = false;
    var count = this.filters.length;
    var i = 0;
    
    while((i<count) && (!encontro)) {
        encontro = (this.filters[i].id == idfilter)
        i++;
    }
    
    if (encontro) {
        this.removeChildFromIndex(i-1);
    }
}

function Filter_RemoveChildFromIndex(index)
{
    // elimino todos los filtros hijos
    this.filters[index].clear();
    
    // dejo libre el bucket para un futuro hijo
    var bucket = this.filters[index].bucket;
    this.buckets[bucket] = null;
    
    // saco el filtro de la coleccion global de instancias
    Filter_Instances[this.filters[index].id] = null;
    
    // elimino el filtro de la coleccion de hijos
    this.filters.splice(index, 1);
}

function Filter_Clear()
{
    // this is not a Group Filter
    if(!this.filters)
        return; 
        
    var count = this.filters.length;
    
    for(var i=0; i<count; i++) {
        this.filters[i].clear();
        Filter_Instances[this.filters[i].id] = null;        
    }
    
    this.filters = [];
    this.buckets = [];
}

function Filter_ToXml(root) 
{
    var node = null;
    
    if(this.type == "GROUP"){
        if(this.nexo == "AND")
            node = document.createElement("AndGroupFilter");
        else
            node = document.createElement("OrGroupFilter");
        
        if (this.source != "")
            node.setAttribute("Join", this.source);
        
        for(var i=0; i<this.filters.length; i++) {
            this.filters[i].toXml(node);
        }
    }
    else {
        node = document.createElement("SimpleFilter");
            
        if (this.field != "")
            node.setAttribute("Field", this.field);
        if (this.operation != "")
            node.setAttribute("Operation", this.operation);
        if (this.value != "")
            node.setAttribute("Value", this.value);
        if (this.typeValue != "")
            node.setAttribute("TypeValue", this.typeValue);
    }
    
    root.appendChild(node);
}

function Filter_FromXml(rootNode)
{
    this.clear();
    
    var node = rootNode.firstChild;
    
    switch(node.tagName)
    {
        case "AndGroupFilter":
            this.nexo = "AND";
            this.parseInnerFilters(node.childNodes);
            break;
        case "OrGroupFilter":
            this.nexo = "OR";
            this.parseInnerFilters(node.childNodes);
            break;
        case "SimpleFilter":
            alert("not implemented");
            break;            
    }
}

function Filter_ParseInnerFilters(nodes)
{
    for(var i=0; i<nodes.length; i++)
    {
        var node = nodes[i];
        
        switch(node.tagName)
        {
            case "AndGroupFilter":
                var chilFilter = this.addGroupFilter("AND")
                chilFilter.parseInnerFilters(node.childNodes);
                break;
            case "OrGroupFilter":
                var chilFilter = this.addGroupFilter("OR")
                chilFilter.parseInnerFilters(node.childNodes);
                break;
            case "SimpleFilter":
                this.addConditionFilter(node.getAttribute("Field"), node.getAttribute("Operation"), node.getAttribute("Value"), node.getAttribute("TypeValue"));
                break; 
        }
    }
}

function Filter_NewChild()
{
    var index;

    var i = 0;
    var encontro = false;
    var count = this.buckets.length;
    
    while( (i<count) && (!encontro) ) {
        encontro = (this.buckets[i]==null);
        i++;
    }
    
    if(encontro)
        index = (i-1);
    else
        index = i;
        
    var id = this.id + "_" + index;
    this.buckets[index] = id;
    lastBucket = index;

    return id;    
}